package controller

import (
	"encoding/json"
	"ez/apps/tool/service"
	"ez/apps/wms/auto/controller"
	"ez/apps/wms/conf"
	wms "ez/apps/wms/document"
	"ez/config/code"
	"ez/custom/cc"
	"fmt"
	"gitee.com/dreamwood/ez-go/ez"
	"gitee.com/dreamwood/ez-go/ss"
	"time"
)

type OutLogController struct {
	controller.OutLogAutoController
}

func init() {
	c := &OutLogController{}
	c.SetRouteParam("/wms", "/admin", "OutLog")
	ez.CreateApi(c.AdminGet(), c.GetAction).SetRouterName("[wms]出库记录_创建")
	ez.CreateApi(c.AdminList(), c.ListAction).SetRouterName("[wms]出库记录_列表")
	ez.CreateApi(c.AdminSave(), c.SaveAction).SetRouterName("[wms]出库记录_保存")
	ez.CreateApi(c.AdminCopy(), c.CopyAction).SetRouterName("[wms]出库记录_复制")
	ez.CreateApi(c.AdminUpdate(), c.UpdateAction).SetRouterName("[wms]出库记录_更新")
	ez.CreateApi(c.AdminChoice(), c.ChoiceAction).SetRouterName("[wms]出库记录_选项")
	ez.CreateApi(c.AdminDelete(), c.DeleteAction).SetRouterName("[wms]出库记录_删除")
	ez.CreateApi(c.AdminUnDelete(), c.UnDeleteAction).SetRouterName("[wms]出库记录_恢复")
	ez.CreateApi(c.AdminDestroy(), c.DestroyAction).SetRouterName("[wms]出库记录_销毁")
	ez.CreateApi(c.AdminUpdateMany(), c.UpdateManyAction).SetRouterName("[wms]出库记录_更新_批量")
	ez.CreateApi(c.AdminDeleteMany(), c.DeleteManyAction).SetRouterName("[wms]出库记录_删除_批量")
	ez.CreateApi(c.AdminDestroyMany(), c.DestroyManyAction).SetRouterName("[wms]出库记录_销毁_批量")
	ez.CreateApi(c.AdminApi("/OutLog/out_many"), c.OutManyAction).SetRouterName("[wms]出库记录_批量出库")
	ez.CreateApi(c.AdminApi("/OutLog/out_cancel"), c.OutCancelAction).SetRouterName("[wms]出库记录_出库红冲")
	ez.CreateApi(c.AdminApi("/OutLog/out_back"), c.OutBackAction).SetRouterName("[wms]出库记录_出库退库")
}

// func (c OutLogController) AccessControl(session *ez.Session) { /* 在这里面重构 */ }
// func (c OutLogController) GetAction(session *ez.Session) { /* 在这里面重构 */ }
// func (c OutLogController) ListAction(session *ez.Session) { /* 在这里面重构 */ }
type outCancelQuery struct {
	OutLogId int    `json:"outLogId"`
	Note     string `json:"note"`
	Applier  string `json:"applier"` //经办人
	Pos      string `json:"pos"`
}

func (c OutLogController) OutCancelAction(session *ez.Session) {
	this := cc.New(session)
	query := new(outCancelQuery)
	e := this.FillJson(&query)
	if this.Try(e) {
		return
	}
	//校验数据合理性 //todo 这里没有强行校验 是否有出库数量，为了增加易用性
	crud := wms.NewOutLogCrud()
	outLogOrg, e := crud.FindOneBy(ss.M{"id": query.OutLogId}, nil)
	if this.CheckError(e) {
		return
	}
	if outLogOrg.Id == 0 {
		this.ReturnError(code.Error, "请选择有效入库数据", "OutLogId")
		return
	}
	//创建红冲数据
	cancelLog := new(wms.OutLog)
	jsonFind, e := json.Marshal(outLogOrg)
	if this.Try(e) {
		return
	}
	if this.Try(json.Unmarshal(jsonFind, &cancelLog)) {
		return
	}
	//cancelLog.CreateFromString(outLogOrg.ToString())
	cancelLog.Id = 0
	cancelLog.CreateAt = time.Now()
	cancelLog.Note = query.Note
	cancelLog.TypeId = conf.OutCancelTpeId
	//cancelLog.Type = &models.IOType{Id: conf.OutCancelTpeId}
	cancelLog.DepartmentId = outLogOrg.DepartmentId
	cancelLog.IsCanceled = true
	cancelLog.Num = cancelLog.NumCanBack * -1
	cancelLog.NumCanBack = 0
	cancelLog.Cost = cancelLog.Num * cancelLog.BatchPrice

	//同时标记原始记录的
	outLogOrg.IsCanceled = true

	//恢复原始入库数据
	inLogCrud := wms.NewInLogCrud()
	inLog, e := inLogCrud.FindOneBy(ss.M{"heapCode": cancelLog.HeapCode}, nil)
	if this.CheckError(e) {
		return
	}
	if inLog.Id == 0 {
		this.ReturnError(code.ErrorNotFound, "原始入库记录未找到，操作取消", "")
		return
	}
	if inLog.NumOut < outLogOrg.Num {
		this.ReturnError(code.ErrorNotFound, "数据异常，出库数量大于原入库记录", ss.M{
			"inlog":     inLog,
			"outLogOrg": outLogOrg,
		})
		return
	}
	inLog.NumOut -= outLogOrg.NumCanBack
	inLog.NumLeft += outLogOrg.NumCanBack

	cancelLog.Link = ""
	cancelLog.LinkTo = outLogOrg.Link

	outLogOrg.SetEvent(true)
	_ = outLogOrg.Save()

	cancelLog.SetEvent(true)
	_ = cancelLog.Save()

	inLog.SetEvent(true)
	_ = inLog.Save()

	this.ReturnSuccess("OK", "")

}

type OutQuery struct {
	List []struct {
		InLogId int     `json:"inLogId"`
		Num     float64 `json:"num"`
		//以下都是无用数据，因为inlog必须获取才能使用
		ItemId   int64  `json:"itemId"`
		ItemCode string `json:"itemCode"`
		ItemText string `json:"itemText"`
		ItemPos  string `json:"itemPos"`
		HeapCode string `json:"heapCode"`
	} `json:"list"`
	Model wms.OutLog `json:"model"`
}

func (c OutLogController) OutManyAction(session *ez.Session) {

	this := cc.New(session)
	query := new(OutQuery)
	e := this.FillJson(query)
	if this.CheckError(e) {
		return
	}
	//逐条拆解到出库记录
	if len(query.List) == 0 {
		this.ReturnError(code.Error, "未选择任何记录", "")
		return
	}
	if query.Model.TypeId == 0 {
		this.ReturnError(code.Error, "请选择出库类型", "")
		return
	}
	//本次循环只是检查数据什么业务也不做
	crudInLog := wms.NewInLogCrud()
	toSaveIn := make([]wms.InLog, 0)
	toSaveOut := make([]wms.OutLog, 0)

	if query.Model.Sn == "" {
		//创建批次号
		query.Model.Sn = service.CreateSnByString(
			ez.ConfigService.AppId,
			"StoreOutSn:[YY][MM][DD][DMAX[3]]",
			1)[len("StoreOutSn:"):]
	}

	for _, row := range query.List {
		if row.Num == 0 {
			this.ReturnError(code.Error, fmt.Sprintf("%s数量为0", row.ItemText), "")
			return
		}
		outLog := new(wms.OutLog)
		outLog.ItemId = row.ItemId
		inLogOrg, e := crudInLog.FindOneBy(ss.M{"id": row.InLogId}, nil)
		if this.CheckError(e) {
			return
		}
		if inLogOrg.Id == 0 {
			this.ReturnError(code.Error, fmt.Sprintf("%s入库数据丢失，ID:%d", row.ItemText, row.InLogId), "")
			return
		}
		if inLogOrg.NumLeft < row.Num {
			this.ReturnError(code.Error, fmt.Sprintf("%s出库数据大于库存，ID:%d", row.ItemText, row.InLogId), "")
			return
		}
		inLogOrg.LoadItem()

		outLog.BatchCode = inLogOrg.BatchCode
		outLog.Num = row.Num
		outLog.NumCanBack = row.Num
		outLog.BatchPrice = inLogOrg.BatchPrice
		//单价与入库记录一致，只是一个保留一定位数小数的参考值
		//--最终费用是一个严格的财务数据，但是每一个批次的最后那次出库数据可能会不准确
		if row.Num == inLogOrg.NumLeft {
			//本次出库后这条记录将出库完毕
			outLog.Cost = inLogOrg.CostReal - inLogOrg.NumOut*inLogOrg.BatchPrice
		} else {
			outLog.Cost = row.Num * inLogOrg.BatchPrice
		}
		inLogOrg.NumLeft -= row.Num
		inLogOrg.NumOut += row.Num
		outLog.TypeId = query.Model.TypeId
		outLog.Sn = query.Model.Sn
		outLog.Applier = query.Model.Applier
		outLog.Usage = query.Model.Usage
		outLog.Note = query.Model.Note

		outLog.DepartmentId = query.Model.DepartmentId
		outLog.HeapCode = inLogOrg.HeapCode
		outLog.Pos = inLogOrg.Pos
		outLog.LinkTo = inLogOrg.Link

		toSaveIn = append(toSaveIn, *inLogOrg)
		toSaveOut = append(toSaveOut, *outLog)
	}
	for _, log := range toSaveOut {
		log.SetEvent(true)
		_ = log.Save()
	}
	for _, log := range toSaveIn {
		log.SetEvent(true)
		_ = log.Save()
	}

	this.ReturnSuccess("OK", ss.M{"in": toSaveIn, "out": toSaveOut})
}

type outBackQuery struct {
	ItemId   int64   `json:"itemId"`
	OutLogId int64   `json:"outLogId"`
	Num      float64 `json:"num"`
	Note     string  `json:"note"`
	Applier  string  `json:"applier"`
	Pos      string  `json:"pos"`
}

func (c OutLogController) OutBackAction(session *ez.Session) {
	this := cc.New(session)
	//退库
	query := new(outBackQuery)
	e := this.FillJson(&query)
	if this.CheckError(e) {
		return
	}
	//处理退库
	outLog := new(wms.OutLog)
	outLog.Num = query.Num * -1
	outLog.Pos = query.Pos
	outLog.TypeId = conf.OutBackTpeId
	outLog.Note = query.Note
	outLog.Usage = conf.OutBackUsage
	outLog.CreateName = query.Applier

	inLog := new(wms.InLog)
	inLog.Note = query.Note
	inLog.Pos = query.Pos
	inLog.TypeId = conf.InBackTpeId
	inLog.DepartmentId = outLog.DepartmentId
	//只设置剩余，NumIn 应该为0
	inLog.NumLeft = query.Num
	inLog.NumInReal = query.Num
	if query.ItemId > 0 {
		//无单据退库，相当于入库
		//但是出库这里需要加一条负数记录
		//检验itemId是否是有效数据
		itemCrud := wms.NewItemSkuCrud()
		find, _ := itemCrud.FindId(query.ItemId)
		if find.Id == 0 {
			this.ReturnError(code.ErrorNotFound, "物品ID无效", query.ItemId)
			return
		}
		//--加入负数出库记录
		outLog.ItemId = query.ItemId
		outLog.Applier = query.Applier

		//--加入入库记录
		inLog.ItemId = query.ItemId
		inLog.Supplier = query.Applier

	} else if query.OutLogId > 0 {
		//有出库记录的退库
		outCrud := wms.NewOutLogCrud()
		orgOutLog, _ := outCrud.FindId(query.OutLogId)
		if orgOutLog.Id == 0 {
			this.ReturnError(code.ErrorNotFound, "出库ID无效", query.ItemId)
			return
		}

		if orgOutLog.NumCanBack < query.Num {
			this.ReturnError(code.Error, "超额退库！", query.ItemId)
			return
		}
		orgOutLog.NumCanBack -= query.Num
		outLog.ItemId = orgOutLog.ItemId
		outLog.BatchCode = orgOutLog.BatchCode
		outLog.BatchPrice = orgOutLog.BatchPrice
		//计算退库价值
		if query.Num == orgOutLog.Num {
			outLog.Cost = orgOutLog.Cost * -1
		} else if query.Num > orgOutLog.Num {
			this.ReturnError(code.Error, "退库数量大于原始数量", query.ItemId)
			return
		} else {
			outLog.Cost = query.Num * orgOutLog.BatchPrice * -1
		}

		outLog.HeapCode = orgOutLog.HeapCode
		outLog.DepartmentId = orgOutLog.DepartmentId

		//入库的恢复
		inLog.ItemId = orgOutLog.ItemId
		inLog.BatchPrice = orgOutLog.BatchPrice
		inLog.BatchCode = orgOutLog.BatchCode
		inLog.DepartmentId = orgOutLog.DepartmentId
		//计算入库价值
		if query.Num == orgOutLog.Num {
			inLog.CostReal = orgOutLog.Cost
		} else {
			inLog.CostReal = query.Num * orgOutLog.BatchPrice
		}
		//因为是退库 没有发生价值变动,所以inLog.Cost = 0
		//inLog.Cost = 0

		inLog.HeapCode = orgOutLog.HeapCode
		inLog.LinkTo = orgOutLog.Link
		outLog.LinkTo = orgOutLog.Link
		orgOutLog.SetEvent(true)
		_ = orgOutLog.Save()
	} else {
		this.ReturnError(code.Error, "无效数据", "")
		return
	}
	outLog.SetEvent(true)
	_ = outLog.Save()
	inLog.SetEvent(true)
	_ = inLog.Save()

	this.ReturnSuccess("OK", query)
}
